import { _decorator, tween, Tween, Vec3 } from 'cc';
import { DataProxy } from '../../../frame/A-LIB/sources/lib.b.data';
import GameDC from '../../data/data.game.center';
import { Drawer } from './drawer';
import { Tile } from './tile';
const { ccclass, property } = _decorator;

@ccclass('DrawerStore')
export class DrawerStore extends Drawer {

	private limit = 1;

	public get residue(){
		return this.capacity - this.record_list.length - this.limit;
	}

	protected onLoad(){
		super.onLoad();
		this.capacity = 8;
	}

	protected start(){
		super.start();
		this.initLimit();
	}

	protected getNext(tile: Tile, out?: Vec3){
		if(!this.base_height){
			this.base_height = tile.convertToViewSpaceAR(Vec3.ZERO).y;
			this.base_height = mtec.number.fixedNum(this.base_height, 4);
		}
		let index = this.tile_list.length;
		for(let i = this.tile_list.length-1; i>=0; i--){
			if(this.tile_list[i].ID == tile.ID){
				index = i+1;
				break;
			}
		}
		let position = this.getPostionByIndex(index, out);
		return { index, position };
	}

	protected async afterPadded(record: typeof this.record_list[number]){
		let bucket: Map<string, Tile[]> = new Map();

		this.tile_list.forEach(t=>{
			let token = this.record_list.find(r=>r.tile==t).token;
			if(this.adding_tile.find(el=>el.token==token)) return void 0;

			let id = t.ID;
			if(!bucket.has(id)) bucket.set(id, []);
			bucket.get(id).push(t);
		});

		let trash: Tile[][] = [];
		bucket.forEach(ls=>ls.length>=3 ? trash.push(ls.sort((a,b)=>a.node.position.x-b.node.position.x).splice(0, 3)) : void 0);

		await this.refresh();
		if(trash.length>0){
			await trash.forWait(group=>this.removeOneGroupTile(group));
			await this.refresh();
		}

		let full = this.residue<=0;

		if(full){
			for(let group = new Map<string, number>(), i = 0; i<this.tile_list.length; i++){
				let id = this.tile_list[i].ID;
				if(!group.has(id)) group.set(id, 0);
				group.set(id, group.get(id)+1);

				if(group.get(id)>=3){
					full = false;
					break;
				}
			}
		}

		this.padded_call_list.forEach(call=>call(record, full));
	}

	private removeOneGroupTile(group: Tile[]){
		let center_pos = group[1].node.position.clone();
		center_pos.y += this.tile_size.height * 0.5;

		let duration = 0.2;
		let np = new mtec.NudityPromise<'end'>();
		group.forEach(tile=>{
			this.removeRecordByTile(tile);

			Tween.stopAllByTarget(tile.node);

			tween(tile.node)
			.to(duration, {position: center_pos}, {easing: 'cubicOut'})
			.set({active: false})
			.call(()=>np.resolve('end'))
			.start();
		});

		np.promise.then(()=>{
			this.remove_call_list.forEach(call=>call(group, this.uitrans.convertToWorldSpaceAR(center_pos)));
		});

		return np.promise;
	}

	private remove_call_list: Array<(ls: Tile[], pos: Vec3)=>any> = [];
	public onRemoveTiles(call: (list: Tile[], world_position: Vec3)=>any){
		this.remove_call_list.push(call);
	}

	private padded_call_list: Array<(record: typeof this.record_list[number], full: boolean)=>any> = [];
	public onPadded(call: (record: typeof this.record_list[number])=>any){
		this.padded_call_list.push(call);
	}

	public unshiftTile(count: number){
		count = Math.min(count, this.tileCount);

		if(count <= 0) return [];

		let list = this.tile_list
		.filter(t=>{
			let token = this.record_list.find(r=>r.tile==t).token;
			return !this.adding_tile.find(el=>el.token==token);
		}).splice(0, count).map(t=>this.removeRecordByTile(t));

		this.refresh();

		return list;
	}

	public popLastRecord(){
		if(this.record_list.length<=0) return void 0;

		let record: typeof this.record_list[number];
		let index: number;
		for(let i = this.record_list.length-1; i>=0; i--){
			let token = this.record_list[i].token;
			if(this.adding_tile.find(el=>el.token==token)) continue;

			record = this.record_list[i];
			index = i;
			break;
		}

		if(record){
			this.removeRecordByTile(record.tile);
			this.refresh();
		}

		return record;
	}

	private initLimit(){
		if(GameDC.User.drawer_lock){
			this.limit = 1;
			let reg = DataProxy.follow(GameDC.User, 'drawer_lock', (_, lock)=>{
				if(lock){
					return void 0;
				}

				DataProxy.cancel(reg);
				this.limit = 0;
			}, false);
		}else{
			this.limit = 0;
		}
	}
}
